package net.jueb.majong.voice.controller.voice;

import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.WebAsyncTask;
import org.springframework.web.multipart.MultipartFile;

import net.jueb.majong.core.common.JsonResult;
import net.jueb.majong.voice.controller.AbstractBaseController;
import net.jueb.majong.voice.util.Config;
import net.jueb.util4j.bytesStream.InputStreamUtils;
import net.jueb.util4j.jvm.JvmUtil;
import net.jueb.util4j.thread.NamedThreadFactory;

@Controller
@RequestMapping("/voice")
public class VoiceController extends AbstractBaseController {

	/**
	 * 语音保存后缀
	 */
	private String VoiceSuffix=".voice";

	private final SimpleDateFormat sdf=new SimpleDateFormat("yyyyMMddHH");
	private final DecimalFormat df=new DecimalFormat("######");
	private final AtomicInteger seq=new AtomicInteger();
	
	/**
	 * 文件保留时间
	 */
	private long keepTime=TimeUnit.MINUTES.toMillis(Config.VOICE_KEEP_TIME_MINUTES);
	
	/**
	 * 清理线程池
	 */
	protected final ScheduledExecutorService cleanExecutor=new ScheduledThreadPoolExecutor(1,new NamedThreadFactory("cleanExecutor", true));
	
	/**
	 * 格式化线程池
	 */
	protected final Executor formatExecutor=Executors.newFixedThreadPool(4,new NamedThreadFactory("formatExecutor", true));
	
	{
		Runnable cleanTask=new Runnable() {
			@Override
			public void run() {
				try {
					if(Config.VOICE_CLEAN)
					{
						clean(Config.VOICE_DIR);
						clean(Config.VOICE_FORMAT_DIR);
					}
				} catch (Throwable e) {
					log.error(e.getMessage(),e);
				}
			}
			protected void clean(String dir)
			{
				File voiceDir=new File(dir);
				if(voiceDir.exists() && voiceDir.isDirectory())
				{
					for(File file:voiceDir.listFiles())
					{
						if(System.currentTimeMillis()-file.lastModified()>keepTime)
						{
							log.debug("清理音频文件:"+file);
							file.delete();
						}
					}
				}
			}
		};
		cleanExecutor.scheduleAtFixedRate(cleanTask, 10, 30,TimeUnit.SECONDS);
	}
	
	protected String getVoiceDate()
	{
		String id=sdf.format(new Date())+df.format(seq.incrementAndGet());
		return id;
	}
	/**
	 * 16位id,保证一个小时内100W的id
	 * @return
	 */
	protected String getVoiceId()
	{
		String id=df.format(JvmUtil.getPid())+df.format(seq.incrementAndGet());
		return id;
	}
	
	/**
	 * 转码为mp3,如果不存在语音或者转码失败则返回null
	 * @param voiceId 语音ID
	 * @return
	 */
	protected File formatVoiceToMp3(String voiceId)
	{
		File mp3VoiceFile=null;
		String voiceFileName=voiceId + VoiceSuffix;
		File voiceFile=new File(Config.VOICE_DIR,voiceFileName);
		if(voiceFile.exists())
		{
			String mp3VoiceName=voiceId + ".mp3";
			mp3VoiceFile = new File(Config.VOICE_FORMAT_DIR,mp3VoiceName);
			voiceConvert(voiceFile, mp3VoiceFile, "mp3", getMp3Attrs());
		}
		return mp3VoiceFile;
	}
	
	/**
	 * 异步转码
	 * @param voiceId
	 */
	protected void asyncFormat(String voiceId)
	{
		formatExecutor.execute(new Runnable() {
			@Override
			public void run() {
				formatVoiceToMp3(voiceId);
			}
		});
	}
	
	
	/**
	 * 上传语音
	 * @param file
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/uploadBody", method = { RequestMethod.POST })
	@ResponseBody
	public WebAsyncTask<JsonResult> upload(HttpServletRequest request,boolean sync) {
		return buildTask(new Callable<JsonResult>() {
			@Override
			public JsonResult call() throws Exception {
				JsonResult result = new JsonResult(0);
				byte[] data=InputStreamUtils.getBytes(request.getInputStream());
				String id = getVoiceDate()+getVoiceId();
				String voiceFileName=id + VoiceSuffix;
				File voiceDir=new File(Config.VOICE_DIR);
				if(!voiceDir.exists())
				{
					voiceDir.mkdirs();
				}
				File voiceFile=new File(voiceDir,voiceFileName);
				try {
					FileUtils.writeByteArrayToFile(voiceFile, data);
					log.debug("保存语音文件:"+voiceFile.getPath());
				} catch (Exception e) {
					log.error(e.getMessage(), e);
				}
				if(voiceFile.exists())
				{
					if(sync)
					{//同步
						File mp3VoiceFile = formatVoiceToMp3(id);
						if (mp3VoiceFile!=null && mp3VoiceFile.exists()) 
						{
							result.setCode(1);
							result.setResult(id);
						}
					}else
					{
						result.setCode(1);
						result.setResult(id);
						asyncFormat(id);//异步转码
					}
				}
				return result;
			}
		});
	}
	
	/**
	 * 上传语音
	 * @param file
	 * @param request
	 * @return
	 */
	@RequestMapping(value = "/upload", method = { RequestMethod.POST })
	@ResponseBody
	public WebAsyncTask<JsonResult> upload(@RequestParam(value = "file") MultipartFile file,
			HttpServletRequest request,boolean sync) {
		return buildTask(new Callable<JsonResult>() {
			@Override
			public JsonResult call() throws Exception {
				JsonResult result = new JsonResult(0);
				if (file.isEmpty()) 
				{
					return new JsonResult(0, "file.isEmpty");
				}
				String id = getVoiceDate()+getVoiceId();
				String voiceFileName=id + VoiceSuffix;
				File voiceDir=new File(Config.VOICE_DIR);
				if(!voiceDir.exists())
				{
					voiceDir.mkdirs();
				}
				File voiceFile=new File(voiceDir,voiceFileName);
				try {
					file.transferTo(voiceFile);
					log.debug("保存语音文件:"+voiceFile.getPath());
				} catch (Exception e) {
					log.error(e.getMessage(), e);
				}
				if(voiceFile.exists())
				{
					if(sync)
					{//同步
						File mp3VoiceFile = formatVoiceToMp3(id);
						if (mp3VoiceFile!=null && mp3VoiceFile.exists()) 
						{
							result.setCode(1);
							result.setResult(id);
						}
					}else
					{
						result.setCode(1);
						result.setResult(id);
						asyncFormat(id);//异步转码
					}
				}
				return result;
			}
		});
	}
	
	/**
	 * 查找转码语音文件
	 * @param voiceId
	 * @param format
	 * @return
	 */
	protected File findFormatVoiceFile(String voiceId,String format)
	{
		String formatVoiceName=voiceId + "."+format;
		File formatVoiceFile = new File(Config.VOICE_FORMAT_DIR,formatVoiceName);
		return formatVoiceFile;
	}
	/**
	 * 获取语音
	 * @param request
	 * @param response
	 * @return
	 * @throws IOException 
	 */
	@RequestMapping(value = "/download", params = {"id"})
	public void download(HttpServletRequest request, HttpServletResponse response, String id) throws IOException {
		String voiceFileName=id + VoiceSuffix;
		File voiceFile=new File(Config.VOICE_DIR,voiceFileName);
		if (voiceFile.exists()) 
		{
			byte[] data = FileUtils.readFileToByteArray(voiceFile);
			responseFile(response,voiceFileName,data);
			return ;
		}
		response.sendError(404);
		log.debug("没有找到语音数据,id="+id);
	}
	
	/**
	 * 获取mp3语音格式
	 * @param request
	 * @param response
	 * @return
	 * @throws IOException 
	 */
	@RequestMapping(value = "/downloadMp3", params = {"id"})
	public void downloadMp3(HttpServletRequest request, HttpServletResponse response, String id) throws IOException {
		File mp3VoiceFile = findFormatVoiceFile(id,"mp3");
		if (mp3VoiceFile.exists()) 
		{
			byte[] data = FileUtils.readFileToByteArray(mp3VoiceFile);
			responseFile(response, mp3VoiceFile.getName(), data);
			return ;
		}
		response.sendError(404);
		log.debug("没有找到语音数据,id="+id);
	}
}
